#ifndef _BOARD_H_
# define _BOARD_H_

typedef unsigned long long BoardCase;

# define SET_COLOR(Value)			(((BoardCase)Value) & 0x00000000000000FF)
# define SET_ALIGN_ALLY(Value)		(((BoardCase)Value) & 0x000000000000FF00)
# define SET_ALIGN_ENMY(Value)		(((BoardCase)Value) & 0x0000000000FF0000)
# define SET_ALIGN_NUMBER(Value)	(((BoardCase)Value) & 0x00000000FF000000)
# define SET_POSITION_X(Value)		((((BoardCase)Value) << 32) & 0x000000FF00000000)
# define SET_POSITION_Y(Value)		((((BoardCase)Value) << 40) & 0x0000FF0000000000)
# define SET_SURROUNDED(Value)		(((BoardCase)Value) & 0x00FF000000000000)

# define GET_COLOR(Case)			(((BoardCase)Case) & 0x00000000000000FF)
# define GET_ALIGN_ALLY(Case)		(((BoardCase)Case) & 0x000000000000FF00)
# define GET_ALIGN_ENMY(Case)		(((BoardCase)Case) & 0x0000000000FF0000)
# define GET_ALIGN_NUMBER(Case)		(((BoardCase)Case) & 0x00000000FF000000)
# define GET_POSITION_X(Case)		(((BoardCase)Case) & 0x000000FF00000000)
# define GET_POSITION_Y(Case)		(((BoardCase)Case) & 0x0000FF0000000000)
# define GET_SURROUNDED(Case)		(((BoardCase)Case) & 0x00FF000000000000)

# define CONVERT_POSITION_X(Value)	((BoardCase)(Value >> 32))
# define CONVERT_POSITION_Y(Value)	((BoardCase)(Value >> 40))

# define COLOR_BLACK				0x0000000000000000
# define COLOR_WHITE				0x0000000000000001
# define COLOR_NONE					0x0000000000000002
# define COLOR_COUNT				0x03 // Color can't be >= to this value

# define ALLY_NONE					0x0000000000000000
# define ALLY_LEFT					0x0000000000000100
# define ALLY_RIGHT					0x0000000000000200
# define ALLY_UP					0x0000000000000400
# define ALLY_DOWN					0x0000000000000800
# define ALLY_UP_LEFT				0x0000000000001000
# define ALLY_UP_RIGHT				0x0000000000002000
# define ALLY_DOWN_LEFT				0x0000000000004000
# define ALLY_DOWN_RIGHT			0x0000000000008000

# define ENMY_NONE					0x0000000000000000
# define ENMY_LEFT					0x0000000000010000
# define ENMY_RIGHT					0x0000000000020000
# define ENMY_UP					0x0000000000040000
# define ENMY_DOWN					0x0000000000080000
# define ENMY_UP_LEFT				0x0000000000100000
# define ENMY_UP_RIGHT				0x0000000000200000
# define ENMY_DOWN_LEFT				0x0000000000400000
# define ENMY_DOWN_RIGHT			0x0000000000800000

# define IS_SURROUNDED				0x0001000000000000

// ALIGN_NUMBER						0x00000000XX000000

// POSITION_X						0x000000XX00000000

// POSITION_Y						0x0000XX0000000000

// SURROUNDED						0x00XX000000000000

# define DIRECTION_LEFT				1
# define DIRECTION_RIGHT			2
# define DIRECTION_UP				3
# define DIRECTION_DOWN				4
# define DIRECTION_UP_LEFT			5
# define DIRECTION_UP_RIGHT			6
# define DIRECTION_DOWN_LEFT		7
# define DIRECTION_DOWN_RIGHT		8

class Board
{
public:
	static BoardCase const WIDTH;
	static BoardCase const HEIGHT;
private:
	BoardCase** m_cases;
	int m_width;
	int m_height;

public:
	Board(int _width = 0, int _height = 0);
	Board(Board const&);
	Board(Board const& _source, int _x, int _y, int _width, int _height);
	~Board();
	
	void init();

	static void PrintCase(BoardCase const& _case);
	bool CanIMove(unsigned int _dest_y, unsigned int _dest_x, BoardCase _color, bool _verbose = false);
	void CapturePieces(BoardCase& _case);
	void UpdateCaseState(BoardCase& _case, bool _updateAll = true);
	BoardCase** getCases();
	int getWidth() const;
	int getHeight() const;
	void setCases(BoardCase** _cases);
	BoardCase* GetAdjacentCase(int _x, int _y, int _direction);
	void ClearCase(BoardCase& _case, int _x, int _y);
	
	static void CreateNewBoardCase(BoardCase& _dst, BoardCase _color, BoardCase _x, BoardCase _y, BoardCase _alignEnnemy, BoardCase _alignAlly, BoardCase _surrounded);
	static BoardCase ConvertDirectionToAlly(int _direction);
	static BoardCase ConvertDirectionToEnnemy(int _direction);
	static int ConvertAllyToDirection(BoardCase _allyAlign);
	static int ConvertEnnemyToDirection(BoardCase _ennemyAlign);
	static int GetXIncrementFromDirection(int _direction);
	static int GetYIncrementFromDirection(int _direction);
	static int GetOppositeDirection(int _direction);
	static void GetCasePosition(BoardCase& _case, int& _x, int& _y);
	static bool CheckIfSurrounded(BoardCase& _case);

public:
	__declspec(property(get=getCases, put=setCases))BoardCase** Cases;
	__declspec(property(get=getWidth))int Width;
	__declspec(property(get=getHeight))int Height;

private:
	Board& operator=(Board const&);
};

#endif // _BOARD_H_
